DiskReader
DiskReader is a short, concise piece of code which contains all the basic
requirements of a system friendly disk imager. All you have to do is insert
an include diskreader.asm at the top of your program.
The general concept is that you read one track, decode it, save it, read
another and so on. This track is either DOS readable or held in a raw
format that is word-synchronized, this covers 99% of disk formats used in
games. You can either write to a single diskfile, or write several files.
Diskreader may seem restricitive, and it is - but there are very few disk
reading requirements which cannot be solved this way. If you need an extra
feature (like seeking backwards in the disk file, saving several files in
more than one chunk) then simply add the required code yourself in the
ripper, I quite allow it.
download diskreader.asm, or adfreader.asm which is a 100% compatible
replacement for diskreader, except that it sources data from an ADF disk
image file, rather than the trackdisk device.
Writing installers with diskreader
Initial decisions: diskreader.asm has some special flags which you
can define before including it. To specify, for example, FILEMODE
to be on, write FILEMODE=1 in your code. To prevent switching on
FILEMODE, either write FILEMODE=0, or simply do not write
it.
- TRACKMODE=1: This says 'I will only read DOS tracks'.
This enables the user to choose the device instead of it just being
trackdisk. The RAWREAD and RESYNC macros and the
__rawrd and __sync functions are removed.
- FILEMODE=1: This says 'I will save several files and I
will choose their names myself'. The user may no longer specify the name of
an image file to create - instead, you save individual files with their
filenames. The __write function and the WRITE and
WRITEDOS macros are removed, and a new SAVEF macro and
__savef function are included.
- MESSAGES=1: This simply makes the RAWREAD and
DOSREAD macros (and corresponding functions) print out to the user
the track they are about to read, the cursor is kept on the same line. This
makes a very simple progress indicator.
Now include diskreader.asm. You can now start writing code to read
the disk. For example,
WRITEDOS #0
WRITEDOS #1
moveq #2,d7 ; d7 = tracknumber
.nxttrk RAWREAD d7 ; read track
RESYNC #$9521 ; resync track
bsr decode ;... not included
beq.s .ok ; checksum ok?
FAILURE cksum(pc)
.ok WRITE #6800
addq.w #1,d7
cmp.w #160,d7
bne.s .nxttrk
rts
cksum dc.b 'bad checksum',0
This program reads tracks 0 and 1 as normal DOS tracks, and writes them to
the diskfile as 5632 bytes each, then reads all the other tracks as raw
tracks with wordsync=$9521, writing them to the diskfile as 6800 bytes
each. If decoding fails, the user sees the message "bad checksum: not a DOS
disk".
As you can see, the reading and writing of disk data is very simple, so the
majority of the code will be the task of decoding the disk data, which was
not included in that example.
Major concepts
- Working with a track buffer: diskreader creates a 32k chipram
BSS area for holding track data. All the read and write macros use this
buffer by default, so your normal method should be to read a track in,
decode it, then write it out. You can access the buffer with the internal
name __trk, or you can use the BUFFER directive to give
another name to it.
- Accepting failure: all routines will, on error, automatically
leave the program (whatever the stack is like) and go to the cleanup
routine. Therefore you should not need to do things like allocate memory,
as there is no guarantee you can get all the way through your program to
free it (instead, use some BSS memory). You are also encouraged to use the
FAILURE macro to quit the reader on your own errors (such as the
disk data failing the checksum).
- Use the internals: all the internal labels and variables of the
diskreader start with two underlines, and they look pretty 'internal' - but
I certainly allow you to access them. For example, the DOS file handle for
the diskimage is held in __outfh(a5), and DOSBase is in
dosbase(a5). You can do anything with DOS and this filehandle you
like. Also, rather than always use the macro RAWREAD, you can set
A0 to the trackbuffer and D0 to the required track, then call
__rawrd.
- Preserve A5 for the routines, don't rely on D0/D1/A0/A1: using
any of the macros or disk routines require that A5 remain intact - it
points to the variables. The usual scratch registers will be trashed, but
all others will be preserved.
Command reference
- BUFFER buffername: Lets you declare a name to access
the trackbuffer with. This is a BSS Chip area which is used by all the
other macros.
- FAILURE [reason]: Fail the reading of the disk.
Everything will be cleaned up and the disk motor will be switched off. You
can optionally specify a parameter which points to a text message to print
to the user.
- DOSREAD track: This will read the 5632 bytes of the
disk track specified into the start of the track buffer.
- RAWREAD track: This will read 32766 bytes of raw,
undecoded disk data stream from the track specified, into the whole track
buffer. This large a stream guarantees that there is at least one entire
copy of the track in question, so you can therefore search forwards to find
the first matching bitstream and assume that this is correct - you are best
to use the RESYNC macro to do this. This macro is not available in
TRACKMODE.
- RESYNC wordsync: This will search through the bitstream
contained in the track buffer for the specified wordsync value and - if it
finds it - will shift all the data in the the bitstream backwards so that
the first word of the track buffer is now the matched wordsync. This macro
is not available in TRACKMODE.
- WRITE length, [offset]: This will save to this diskfile
the specified number of bytes from the start of the track buffer. If the
offset parameter is specified, the bytes saved will start at this
offset in the track buffer. This macro is not available in
FILEMODE.
- WRITEDOS track: This macro simply reads the specified
DOS track, and writes it straight to the diskfile. This macro is not
available in FILEMODE.
- SAVEF filename, buffer, length: This will save any
particular length of bytes from any particular buffer to a file with the
given filename. This macro is only available in FILEMODE.
Examples
Kyzer/CSG